package com.bym.mall.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bym.mall.consts.RedisPrefixConst;
import com.bym.mall.entity.User;
import com.bym.mall.enums.ResponseEnum;
import com.bym.mall.enums.RoleEnum;
import com.bym.mall.mapper.UserMapper;
import com.bym.mall.service.ICartService;
import com.bym.mall.service.IUserService;
import com.bym.mall.utils.HttpUtil;
import com.bym.mall.vo.ResponseVo;
import com.bym.mall.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author bym
 * @since 2022-03-22
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private ICartService cartService;

    @Resource
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 注册
     *
     * @param user 用户
     */
    @Override
    public ResponseVo register(User user) {
        //username不能重复
        int countByUsername = userMapper.countByUsername(user.getUsername());
        if (countByUsername > 0) {
            return ResponseVo.error(ResponseEnum.USERNAME_EXIST);
        }

        //email不能重复
        int countByEmail = userMapper.countByEmail(user.getEmail());
        if (countByEmail > 0) {
            return ResponseVo.error(ResponseEnum.EMAIL_EXIST);
        }

        //生成盐值
        String salt = RandomUtil.randomNumbers(6);
        //MD5摘要算法
        String password = getMd5Pwd(user.getPassword(), salt);
        user.setPassword(password);
        user.setSalt(salt);

        //默认新用户为普通用户
        user.setRole(RoleEnum.CUSTOMER.getCode());

        //写入数据库
        int resultCount = userMapper.insert(user);
        if (resultCount == 0) {
            return ResponseVo.error(ResponseEnum.ERROR);
        }

        return ResponseVo.success();
    }

    @Override
    public ResponseVo loginByPwd(String username, String password) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        User user = userMapper.selectOne(queryWrapper);
        if (ObjectUtil.isNull(user)) {
            //用户不存在（返回：用户名或密码错误）
            return ResponseVo.error(ResponseEnum.USERNAME_OR_PASSWORD_ERROR);
        }

        //MD5摘要算法
        String password2 = getMd5Pwd(password, user.getSalt());
        if (!user.getPassword().equalsIgnoreCase(password2)) {
            //用户存在，密码不正确（返回：用户名或密码错误）
            return ResponseVo.error(ResponseEnum.USERNAME_OR_PASSWORD_ERROR);
        }

        //将user -> userVo
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);

        //缓存用户购物车
        cartService.cacheCart(userVo.getId());

        return ResponseVo.success(userVo);
    }

    /**
     * 得到md5密码
     *
     * @param password 密码
     * @param salt     盐值
     * @return {@link String}
     */
    private String getMd5Pwd(String password, String salt) {
        for (int i = 0; i < 3; i++) {
            password = DigestUtil.md5Hex(salt + password + salt, StandardCharsets.UTF_8);
        }
        return password;
    }

    @Override
    public ResponseVo loginByPhoneAndCode(String phone, String code) {
        //判断redis中的code和用户传过来的code是否相等
        String cacheCode = redisTemplate.opsForValue().get(RedisPrefixConst.GET_CODE + phone);
        if (ObjectUtil.isNull(cacheCode)) {
            return ResponseVo.error(ResponseEnum.CODE_EXPIRE);
        }
        if (!code.equals(cacheCode)) {
            return ResponseVo.error(ResponseEnum.CODE_ERROR);
        }

        //从redis中删除code
        redisTemplate.delete(RedisPrefixConst.GET_CODE + phone);

        //通过手机号获取用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        User user = userMapper.selectOne(queryWrapper);

        //将user -> userVo
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);

        //缓存用户购物车
        cartService.cacheCart(userVo.getId());

        return ResponseVo.success(userVo);
    }

    @Override
    public ResponseVo getCode(String phone) {
        //判断该手机号是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        User user = userMapper.selectOne(queryWrapper);
        if (ObjectUtil.isNull(user)) {
            return ResponseVo.error(ResponseEnum.PHONE_ERROR);
        }

        //生成验证码，长度为5的随机数
        String code = RandomUtil.randomNumbers(5);

        //调用阿里云短信服务
        String retMsg = sendCode(phone, code);
        JSONObject retMsgOb = JSONUtil.parseObj(retMsg);
        if ("SUCCESS".equals(retMsgOb.get("message"))) {
            return ResponseVo.error(ResponseEnum.ERROR);
        }

        //将手机号和验证码存入redis
        redisTemplate.opsForValue().set(RedisPrefixConst.GET_CODE + phone, code, 5, TimeUnit.MINUTES);

        return ResponseVo.success(code);
    }

    @Override
    public ResponseVo logout() {
        return cartService.persistCart();
    }

    /**
     * 调用阿里云短信服务
     *
     * @param phoneNumber 电话号码
     * @param code        验证码
     * @return {@link String}
     */
    private String sendCode(String phoneNumber, String code) {
        String host = "https://miitangs09.market.alicloudapi.com";
        String path = "/v1/tools/sms/code/sender";
        String method = "POST";
        String appcode = "ce086bef4f7c4cb49b4b3a5025779354";
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", "APPCODE " + appcode);
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        headers.put("X-Ca-Nonce", UUID.randomUUID().toString());
        Map<String, String> querys = new HashMap<>();
        Map<String, String> bodys = new HashMap<>();
        bodys.put("phoneNumber", phoneNumber);
        bodys.put("smsSignId", "0000");
        bodys.put("smsTemplateNo", "0002");
        bodys.put("verifyCode", code);

        String retMsg = "";
        try {
            HttpResponse response = HttpUtil.doPost(host, path, method, headers, querys, bodys);
            retMsg = EntityUtils.toString(response.getEntity());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return retMsg;
    }
}
